Información general

Diagrama de despliegue

Namespace
Existirán namespaces propios para los servicios de backend, que se organizarán en función de los proyectos o iniciativas registradas por los distintos organismos.
En cada uno de los namespaces, se realizará el despliegue de los microservicios que estén asociados al proyecto o iniciativa.
Para tener un namespace operativo en Openshift deberán seguirse los siguientes pasos:
- Debe solicitarse la creación del namespace al equipo de operaciones mediante una solicitud.
Al hacer la petición debe indicarse el nombre del namespace. El nombre debe coincidir con el nombre del proyecto en git añadiéndole un prefijo que indicará el entorno. Se recomienda consultar la normativa sobre nomenclatura de proyectos en git para evitar problemas durante el despliegue de los microservicios que se encuentren dentro del proyecto git.
Por ejemplo: Si en git tenemos si-proyecto, en openshift deberemos solicitar la creación de los namespaces des-si-proyecto, pru-si-proyecto y pro-si-proyecto.
- Cuando el namespace esté creado se debe abrir una petición a devops para que el equipo deje el namespace preparado para poder iniciar despliegues.
Si un proyecto tiene suficiente envergadura, podrá solicitarse utilizar varios namespaces por entorno. Para ello, debe de solicitarse una autorización de los equipos de operaciones y devops y configurar correctamente las comunicaciones entre estos namespaces. Además, deberán crearse tantos repositorios git como namespaces vayan a utilizarse siguiendo las normas sobre nomenclatura establecidas
Microservicios
Imagen del microservicio
Cada microservicio se empaquetará en una imagen y se ejecutará como un contenedor dentro de un pod.
La imagen base que utilizarán los microservicios será proporcionada por el Área de Infraestructura y deberá formar parte del catálogo de imágenes base ofrecidas por Red Hat excepto en casos debidamente justificados.
La imagen base para microservicios basados en Java y de nuevo desarrollo estará basada en OpenJdk 21.
El gobierno de la imagen base corresponde al área de Infraestructura, siendo responsabilidad de ellos detectar problemas de seguridad y actualizarlas cuando sea necesario.
Cuando una imagen base se actualiza, en desarrollo los equipos serán los responsables de programar y ejecutar el despliegue de los microservicios que utilizan esa imagen base para garantizar que el producto en los entornos no productivos está actualizado. En producción, el equipo de desarrollo será el encargado de solicitar un despliegue de esos microservicios abriendo las peticiones necesarias y siguiendo el protocolo establecido.
Para los proyectos legacy que no dispongan de un equipo de mantenimiento, deberá nombrarse un responsable para ejecutar una actualización de la imagen base cuando sea necesario.
Todos los microservicios contendrán un fichero “.dockerfile” cuya imagen base será la proporcionada por el área de Infraestructura. Este fichero .dockerfile debe estar en la carpeta raíz del microservicio y será responsabilidad de los equipos de desarrollo incorporarlo y mantenerlo.
Para simplificar el gobierno del fichero “.dockerfile”, el activo ada-fwk-ms proporcionará a los microservicios que lo incorporen, un fichero .dockerfile por defecto en los arquetipos maven que el activo publica para simplificar la creación de microservicios.
Pod
Los pods son objetos que representan la unidad básica de despliegue en Kubernetes. Internamente un pod puede estar compuesto de uno o más contenedores.
La lógica de un microservicio se almacena en un único pod. De un pod pueden crearse varias réplicas que permiten distribuir la carga y garantizar la alta disponibilidad. Durante el despliegue del pod debe definirse qué contenedores lo conforman, así como la configuración de estos.
En concreto, los microservicios se desplegarán como pods, en los que para cada entorno se establece un número mínimo de réplicas del pod:
Entorno | Número de réplicas |
Test | 1 |
Preproducción | 3 (Alta disponibilidad) |
Producción | 3 (Alta disponibilidad) |
Para garantizar la alta disponibilidad, deberán verificarse que existen definidos Placement Rules que distribuyan las diferentes réplicas entre todos los cluster disponibles. De esta forma, aunque algún nodo del cluster tenga alguna incidencia, siempre existirán réplicas de los microservicios corriendo en otros nodos.
Para ello deberán existir una serie de recursos y configuraciones para cumplir la alta disponibilidad de las aplicaciones:
HorizontalPodAutoscaler: Este recurso ajusta automáticamente el número de réplicas de un pod en función de la utilización observada de CPU/memoria o de otras métricas seleccionadas. El propósito principal del HPA es asegurar que las aplicaciones puedan manejar cambios en la carga de trabajo sin intervención manual, mejorando así la resiliencia y la eficiencia de los recursos.
Pod anti-affinity: Este recurso va a permitir que las réplicas de cada pod se desplieguen en diferentes nodos asegurando disponibilidad de la aplicación en caso de caída de uno de los nodos donde se encontrara una de las réplicas del pod aplicativo.
Los equipos de desarrollo tienen que identificar cuanto consumo va a hacerse de un microservicio ya que es una información que debe tenerse en cuenta a la hora de solicitar recursos para el namespace.
Despliegue de microservicios
Dependiendo de su naturaleza, pueden existir dos tipos de pods que afectarán a su forma de despliegue:
Microservicio sin estado
Los pods sin estado o stateless, son aquellos que no guardan el estado de la aplicación que contienen, es decir, no guardan datos que necesiten ser conservados tras la eliminación o el reinicio del pod.
El despliegue de este tipo de microservicios permite gestionar las réplicas de un pod de forma dinámica. A la hora de definir un deployment debe configurarse:
Los contenedores que componen el pod.
El dimensionamiento de los pods y el número de réplicas.
Las reglas para automatizar el escalado en base a los picos y valle de uso.
Mecanismos de rollback automatizados para restaurar el servicio en el caso de que el despliegue falle.
Este tipo de despliegue debe usarse en microservicios que no tengan un estado asociado, dando igual qué réplica ejecute el proceso ya que no depende de ningún estado almacenado en un pod concreto.
En el caso que se precise crear un workload sin estado se deberá generar un recurso Deployment, el equipo de desarrollo será el responsable de su creación, mantenimiento y almacenado en el repositorio del aplicativo. De cara al despliegue del aplicativo no se deberá realizar ningún cambio adicional.
Microservicio con estado
En contraste, los pods statefull están diseñados para mantener datos persistentes. Esto se logra utilizando volúmenes persistentes (Persistent Volumes, PV) y Reclamaciones de Volúmenes Persistentes (Persistent Volume Claims, PVC). Los pods con estado suelen ser utilizados para bases de datos, sistemas de archivos distribuidos, y cualquier aplicación que requiera persistencia de datos.
Este tipo de despliegue mantiene fijo el número de réplicas disponibles de un microservicio eliminando la posibilidad de realizar un escalado horizontal. Para este tipo de despliegues solo está disponible el escalado vertical que es el que aumenta y disminuye los recursos asociados al pod dentro de un rango establecido.
Si bien no es ni lo habitual ni lo recomendable, pueden existir motivos para crear un microservicio con estado. En ese caso, las peticiones con el mismo identificador deben procesarse siempre por la misma réplica que es la que tiene almacenado su estado interno.
En el caso que se precise crear un workload con estado se deberá generar un StatefulSet, el equipo de desarrollo será el responsable de su creación, mantenimiento y repositado en el repositorio aplicativo. De cara al despliegue del aplicativo no se deberá realizar ningún cambio adicional.
Servicios
La creación de los servicios se hará mediante el objeto de Kubernetes y con la ayuda de la herramienta que Openshift dispone para facilitar el descubrimiento y acceso a estos servicios.
Todos los servicios existentes en el namespace estarán definidos con un DNS y tendrán un puerto asociado. De esta forma, durante el arranque del microservicio se establecerá una conexión con el servicio de auto-descubrimiento de openshift que permitirá mapear los DNS por IP válidas para establecer la comunicación.
El principal beneficio de usar servicios y el servicio de auto-descubrimiento proporcionado por Openshift es que abstrae a los microservicios de conocer la url física de los componentes con los que se quiere comunicar. Dado que la IP se renueva cada vez que se reinicia el pod y que nunca se conocen cuantas réplicas tiene activo un microservicio, es muy complicado conocer esa información. Gracias al servicio de auto-descubrimiento este proceso es transparente para el microservicio que solo se tiene que preocupar por conocer el DNS y el puerto del servicio con el que se quiere comunicar.
Se publicará como servicio cualquier api que deba ser invocada por otros microservicios o componentes software dentro o fuera del namespace.
El nombrado del servicio se basa en la norma establecida para el nombrado de componentes añadiendo el sufijo -svc.: [S/SA/SI]-[sistema]-[componente]-svc.
En los entornos de desarrollo los equipos serán los responsables de crear y configurar los servicios que requieran los microservicios para su correcto funcionamiento. En producción deberá abrirse una petición a operaciones solicitando la creación o modificación del servicio.
Persistent Volume Claim (PVC)
Un PersistentVolumeClaim es un objeto en Kubernetes que permite solicitar y reservar un recurso de almacenamiento persistente. Un Persistent Volume Claim permite a los pods del microservicio acceder al almacenamiento persistente sin importar el proveedor o la tecnología subyacente.
Un Persistent Volume Claim siempre está asociado a un volumen. Cuando la vinculación con el volumen se realiza con éxito, el pod puede utilizar ese volumen como almacenamiento persistente. El Persistent Volume Claim se encarga de administrar el ciclo de vida del recurso de almacenamiento, lo que incluye la creación, el montaje y la liberación del almacenamiento cuando ya no es necesario.
Solicitud de creación de PVCs para los distintos entornos
Crear una petición desde la tarea de Aprovisionamiento de entornos con los siguientes datos:
- Asunto: Solicitud de creación de PVC - [nombre_del_pvc] en [nombre_del_namespace] - [DES/PRE/PRO]
- Contenido del tique:
- Nombre del PVC: Nombre único para el PVC dentro del namespace.
- Namespace: Namespace donde se debe crear el PVC.
- Tamaño del almacenamiento: Especificad el tamaño en las correspondientes unidades. Por ejemplo: 1Gi.
- Modo de acceso:
- ReadWriteOnce (RWO)
- ReadOnlyMany (ROX)
- ReadWriteMany (RWX)
- Descripción del uso: Breve explicación del propósito del PVC.
Asignar el tique al equipo de operaciones: Derivad el tique al grupo "Cloud-Ops-PEC".
Será necesario subir al repositorio el archivo manifest.yaml donde se defina este PVC, para seguir y cumplir el modelo GitOps.
Para la aplicación del recurso PVC en la plataforma se deberá crear un tique dirigido al equipo de operaciones donde se deberán adjuntar el manifiesto a aplicar o en su defecto incluir la url del repositorio donde se encuentre almacenado.
Volúmenes
Un volumen es un objeto de Kubernetes que permite almacenar información de forma persistente. En un objeto de tipo Volumen se almacena aquella información que no quiere perderse cuando el pod desaparezca.
Un pod puede tener asociado ninguno, uno o varios volúmenes. Los volúmenes son unidades de almacenamiento independientes para cada pod aunque compartida por todos los contenedores que lo forman.
Es posible crear volúmenes que se compartan entre varios pods usando el objeto de Kubernetes PersistentVolumeClaim.
Configuración
La configuración de los microservicios se hará mediante ficheros ConfigMap. Estos ficheros almacenarán las propiedades de configuración de los microservicios. Existirá un único fichero configmap por microservicio en cada entorno y su gobierno es responsabilidad del equipo de desarrollo.
El nombrado de los ficheros ConfigMap se basa en la norma establecida para el nombrado de componentes añadiendo el sufijo “-config.: [S/SA/SI]-[sistema]-[componente]-config.
Siempre que sea posible, este Configmap tendrá la información necesaria para conectarse a un servidor git externo donde se almacene la configuración del microservicio. Existirá un repositorio de configuración por cada namespace. Este repositorio estará organizado por carpetas, una por cada microservicio que se despliegue en el namespace. Dentro de cada una de estas carpetas estarán los ficheros de configuración del microservicio divididos por entornos.
La pipeline de despliegue de los microservicios creará el configmap cuyo contenido para aplicaciones basadas en Spring Boot será el que exista en el fichero application.yml.
En el entorno de desarrollo será responsabilidad de los equipos verificar y comprobar que este fichero se ha creado correctamente cuando ejecuten la pipeline de despliegue. En el entorno de producción deberán establecer mecanismos con el equipo de operaciones para verificar el contenido de dicho fichero y garantizar que el despliegue se ha realizado correctamente.
Secretos
Los secretos almacenan parámetros de configuración con información sensible y que no pueden estar reflejados en claro en un ConfigMap.
Los secretos NO se cifrarán en el entorno de DES o PRU y será responsabilidad de los equipos de desarrollo la gestión y configuración de estos secretos, así como su almacenado en el repositorio de la aplicación para delegar su aplicación a la herramienta ArgoCD. Además, si se observa la existencia de información sensible global para todos los microservicios de un aplicativo se deberá crear un repositorio para ese tenant que contendrá todos los recursos globales de su configuración, como secrets, configmaps, keystores, etc.
Un microservicio puede tener asociado varios secretos. En cada namespace pueden crearse secretos comunes donde se centralicen en un único lugar la información sensible que deba ser compartida por todos los microservicios. Por ejemplo: las credenciales del OTEL Collector.
El gobierno de este repositorio centralizado por namespace será responsabilidad de los proyectos que componen el namespace siendo responsabilidad de ellos determinar qué parámetros son comunes y actualizar sus valores.
Para los entornos de PRE y PRO los secretos se cifrarán y gestionarán usando la herramienta Sealed Secrets.
El equipo de desarrollo abrirá un tique en TEO a los operadores del SI en OCP solicitando los secretos.
El equipo de operación del SI en OCP obtendrá la información de dichos secretos de donde corresponda y poniéndose en contacto con quién corresponda.
El equipo de operación del SI en OCP devolverá al equipo de desarrollo el fichero con los secretos encriptados (convirtiéndolo en un Sealed Secret) para configurarlo en los ficheros de despliegues que correspondan.
Para la creación del TEO se deberán seguir las siguientes indicaciones:
- El tipo de tique es Tarea.
- En el asunto se indicará el SSII y el entorno destino.
- En la descripción se debe de aclarar de donde deben tomar los ficheros en OpenShift, pero recordar el entorno de destino, es decir, deben poner los valores del entorno de Pre.
- Se creará un tique por cada SSII.
OTEL Colector
El OTEL Collector es un componente basado en Open Telemetry cuya principal funcionalidad es recopilar y procesar la información de observabilidad recolectada por cada uno de los componentes desplegados en el namespace.
La información recogida se mandará a los componentes de la Plataforma de Observabilidad para su gestión y visualización.
El principal beneficio de Open Telemetry Collector es que permite aislar a los microservicios y resto de componentes de la Plataforma de Observabilidad. Un microservicio no necesita saber a dónde van a dirigirse las métricas, trazas y logs generados; Open Telemetry Collector centraliza la recolección y manda la información a los diferentes destinos que tiene configurado.
Estos destinos pueden ser las herramientas de observabilidad (Prometheus, Grafana, Jaeger…) definidas en la Plataforma de Observabilidad centralizada o específicas para un namespace concreto. Para los microservicios este proceso no es relevante lo que permite aislarlos simplificando su codificación.
El microservicio enviará al OTEL Collector las métricas, trazas y logs producidas por el código en tiempo de ejecución. Estas métricas, trazas y logs incluyen tanto las que genera automáticamente el framework bajo el que se esté desarrollando, las librerías de tercero que el microservicio incorpore y las generadas programáticamente por el equipo de desarrollo directamente en el microservicio.
Se deja abierta la posibilidad de que si un proyecto necesita un procesamiento personalizado de sus métricas, trazas y logs puedan instalarse en su namespace su propia instalación del componente OTEL Collector. En desarrollo el equipo será el responsable de instalar y mantener este componente. En producción, deberá mantenerlo el equipo de operaciones por lo que previamente deberá solicitarse la autorización del equipo de operaciones antes de realizar esta personalización.
No se usará OTEL Collector para la gestión de las métricas, trazas y logs generadas por el pod a bajo nivel que serán procesadas y enviadas a los servicios de tercero mediante otros mecanismos. Concretamente, para el caso de la recolección de logs de los pods aplicativos, existen pods collectors en cada nodo encargados de recoger y procesar todos los logs de cada pod mostrados por la console output para después ser indexados por la herramienta ElasticSearch. Desde Kibana se podrán visualizar todos los logs de la plataforma, así como crear gráficos y dashboards en caso necesario. Por otro lado, existen unos pods exporter en cada nodo que serán los encargados de recoger todas las métricas de cpu, memoria, i/o, networking, etc y enviarlos a Prometheus para su almacenado. Grafana será la herramienta para la visualización de estas métricas mediante el uso de los dashboards generados por defecto. En caso de que se precise la creación de métricas personalizadas se deberá solicitar la creación de un Grafana (tiene que ser el operador de Grafana de la versión Community) para albergar estas métricas y posibilitar la creación de dashboards personalizados.
Istio (Service Mesh)
Un Service Mesh proporciona funciones de enrutamiento avanzado, balanceo de carga, seguridad y la observabilidad, facilitando la supervisión y la administración de aplicaciones distribuidas. También permiten la implementación de políticas de control de acceso y circuit breaking de manera centralizada, lo que mejora la robustez y la seguridad de las aplicaciones sin requerir cambios en el código de los servicios individuales.
Las Service Mesh simplifican la administración de microservicios, aumentan la confiabilidad y facilitan la implementación de políticas de seguridad, lo que las convierte en una herramienta valiosa para arquitecturas de aplicaciones modernas.
Openshift Service Mesh
En este punto se propone el uso de Openshift Service Mesh el cual es una versión personalizada y adaptada a Openshift de la Service Mesh Istio. Dicha Service Mesh está incluida dentro de Openshift y tiene soporte oficial de Red Hat, por lo que se recomienda encarecidamente el uso de esta versión de Istio.
Istio se basa en el patrón Sidecar, desplegando en todos los pods que forman parte de la Mesh un contenedor, basado en el proxy de envoy, que será el encargado de gestionar todas las comunicaciones del microservicio y de aplicar las reglas establecidas desde el control plane para lograr dotar a los microservicios de funcionalidades adicionales que, de otra forma, deberían implementarse manualmente en el código de lo microservicios.
Este proxy, permite mediante configuración las siguientes herramientas en tiempo real y sin necesidad de modificar código o reiniciar servicios:
- Traffic Management
- Routing: Istio permite configurar un enrutamiento avanzado del tráfico entre servicios. Permitiendo definir reglas para controlar el flujo de las solicitudes a los servicios, como el enrutamiento basado en pesos, cabeceras, enrutamientos específicos para Canary o A/B Testing.
- Load Balancing: Ofrece varios algoritmos de balanceo de carga, incluyendo round robin, least connections y random.
- Traffic Shifting: Facilita la transición gradual del tráfico de una versión de servicio a otra, lo cual es útil para escenarios de Continuos deployment o despliegues tipo Canary.
- Security:
- Mutual TLS (mTLS): Proporciona autenticación de peticiones y cifrado del tráfico mediante mTLS, asegurando la comunicación segura entre Microservicios.
- Authorization: Permite definir políticas de autorización para controlar el acceso a los servicios basados en roles y atributos.
- Identity Management: Permite la integración con sistemas de gestión de identidades para autenticar y autorizar solicitudes.
- Observability:
- Telemetry: Istio recoge métricas de telemetría, registros y trazas de los microservicios, proporcionando una visión detallada del comportamiento de los servicios.
- Distributed Tracing: se integra con sistemas trazabilidad como Jaeger para rastrear solicitudes a través de múltiples servicios y detectar cuellos de botella u otros problemas.
- Logging: Centraliza el registro de eventos y errores, facilitando la monitorización y el diagnóstico de problemas.
- Policy Enforcement:
- Rate Limiting: Permite definir límites para controlar la cantidad de tráfico que puede llegar a un servicio en un periodo de tiempo. Este punto, es muy interesante para utilizarlo con servicios legacy o que no son capaces de gestionar mucha carga.
- Quotas: Gestiona cuotas para limitar el uso de recursos y asegurar una distribución justa.
- Retries and Timeouts: Configura reintentos automáticos y tiempos de espera para las solicitudes fallidas, mejorando la resiliencia del sistema. Es decir, permite indicar los tiempos de recuperación de los sistemas en caso de caída, para que se puedan levantar y recuperar adecuadamente.
- Service Discovery:
- Dynamic Service Discovery: ayuda a detectar automáticamente servicios en ejecución y mantiene un registro actualizado de los servicios disponibles en la malla.
- Fault Injection:
- Fault Tolerance: Simula fallos en los servicios (latencias, errores, etc.) para probar la resiliencia y la tolerancia a fallos de los microservicios.
Aunque, los microservicios podrán implementar sus propias herramientas para gestionar estas funcionalidades, Istio permite la aplicación de estas técnicas de forma transparente al microservicio y de forma homogénea a todos los microservicios facilitando el mantenimiento y la operación.
Modelos de despliegue
OpenShift Service Mesh admite varios modelos de despliegue diferentes para intentar adaptarse de la mejor forma posible a las realidades de los clientes.
Modelo cluster-wide
Este modelo implica que una única instancia de la malla de servicios abarca todo el clúster de Openshift.
Esto significa que solamente se despliega una control-plane de Istio para la gestión de todos los servicios del clúster. Cualquier servicio ubicado en los namespaces del cluster adheridos a la mesh, pueden ser gestionados por esta única instancia, asegurando que las políticas y configuraciones de seguridad y gestión de tráfico se apliquen de manera consistente en todo el entorno.

Este modelo es especialmente adecuado para entornos pequeños o medianos, donde la cantidad de servicios es manejable y la sobrecarga de gestionar una única instancia de malla no es significativa. También es se suele utilizar cuando se busca aplicar una política de seguridad y configuración uniforme en todo el clúster, o cuando un equipo de operaciones prefiere una gestión simplificada y centralizada de la mesh.
La principal ventaja de este enfoque es la facilidad de administración, ya que una única instancia del control-plane simplifica la configuración y reduce la complejidad operativa.
Sin embargo, hay algunas consideraciones a tener en cuenta. En entornos extremadamente grandes o con un número elevado de servicios, una única instancia podría convertirse en un cuello de botella, afectando la escalabilidad. Además, ofrece un menor grado de aislamiento comparado con los despliegues por namespace, lo cual puede ser una limitación si los equipos requieren un alto nivel de independencia. También, cualquier fallo en la malla de servicios centralizada podría tener un impacto más amplio, afectando potencialmente a todo el clúster.
Modelo multi-tenant
En este modelo, múltiples instancias de mesh coexisten gestionando, cada uno, su propio conjunto de namespaces y servicios. Cada equipo o grupo de usuarios, denominado tenant, tiene su propia instancia del control-plane de Istio, lo que les permite tener configuraciones, políticas y recursos independientes.

Este enfoque es ideal para grandes organizaciones donde diferentes equipos necesitan trabajar de forma aislada y segura, sin interferencias entre sí. Por ejemplo, en una empresa con varios departamentos de desarrollo, cada departamento puede tener su propia malla de servicios, permitiéndoles definir y aplicar políticas de seguridad, gestión de tráfico y observabilidad específicas para sus necesidades. Esto también permite la delegación de la administración de la mesh a equipos individuales, reduciendo la sobrecarga operativa centralizada y mejorando la escalabilidad y la resiliencia del sistema.
Una de las principales ventajas del modelo multi-tenant es el alto grado de aislamiento que proporciona. Los recursos y políticas de un tenant no afectan a los de otro, lo que minimiza el riesgo de conflictos y mejora la seguridad. Además, permite una mayor flexibilidad y personalización, ya que cada inquilino puede ajustar sus configuraciones según sus propios requisitos operativos y de seguridad.
Exposición de servicios
Los gateways son los objetos que utiliza Istio para controlar el tráfico de entrada y salida de la mesh. Los gateways permiten centralizar el control del tráfico de uno o varios servicios aplicando sobre ellos diferentes políticas de seguridad, gestión del tráfico, así como diferentes certificados.
También permiten aislar diferentes servicios o aplicaciones, cada uno con su propio Gateway, siendo útil en entornos multi-tenant o en escenarios con diferentes niveles de seguridad.
En resumen, los gateways permiten la centralización o desagregación de las peticiones según sea necesario. El número y la configuración de los gateways dependen de la complejidad de tu entorno y los requisitos específicos de tus aplicaciones y servicios.
A continuación, se muestra un ejemplo avanzado de utilización de Gateways, en el que un Microservicio tiene una parte “privada” y una parte “pública” y se utilizan dos Gateways, uno privado y otro público. Apoyado en los VirtualServices, se logra que desde el Gateway público solamente se tenga acceso a la parte pública de la API y viceversa.

Este enfoque es una demostración de cómo Istio permite gestionar el tráfico y mejorar la seguridad del sistema.
Propuesta
Para nuestro caso de uso se propone un modo de despliegue multi-tenant para gestionar diferentes controlplane para conjuntos de tenant que pertenezcan, por ejemplo, a una consejería de la ADA que tenga sus propias especificaciones de políticas de enrutamiento, sistema de autorización, etc.
Además, dependiendo del contexto de cada tenant, se propone mantener el mTLS habilitado y en modo estricto para proporcionar mayor seguridad al flujo de las peticiones entre pods de la misma mesh, así como proveer de un sistema de autorización mediante la integración a Keycloak para la creación de tokens JWT que proporcione un mecanismo de autorización para los aplicativos.
Se creará un Gateway por cada tenant (normalmente uno por cada namespace) para gestionar el tráfico de entrada y salida, con la información del host de la ruta creada para todos los aplicativos de la mesh y con la configuración TLS para securizar dichas rutas con el certificado que proporcione la ADA para cada ruta. Del mismo modo, se deberá crear un VirtualService por cada microservicio del tenant que tendrá asociado un Gateway, el host de la ruta y el Service destino del aplicativo. Para mejorar el rendimiento se optará por asociar el Service por el puerto HTTP ya que no será necesario añadirle la capa de TLS al mantener por defecto la configuración de mTLS activada.
Comunicaciones
A continuación, se indican los diferentes casos de uso que se identifican para gobernar la comunicación de un microservicio con otros servicios.
Comunicación Frontend - Backend
Este tipo de comunicación normalmente se produce cuando un componente Frontend solicita información a un componente Backend para realizar una tarea. En este caso, dado que el Frontend siempre se ejecuta desde un componente externo (navegador web o aplicación móvil) la petición que el Frontend hace al Backend se considera pública y siempre tiene que hacerse a través de una API publicada en el API Manager y gobernada por la Oficina de Interoperabilidad.
Deberá analizarse, por parte del equipo de desarrollo, qué información debe solicitar el Frontend al Backend y crear las API necesarias, siguiendo los criterios establecidos por la Arquitectura de API, desplegándolas en el API Manager siguiendo las directrices indicadas en el Modelo de Despliegue de API.
La comunicación entre el Frontend y el Backend siempre tiene que estar securizada mediante token JWT, mTLS o algún mecanismo de seguridad similar que garantice que se cumple el principio de Zero Trust, y aunque API Manager haga una comprobación de seguridad el microservicio deberá también hacer sus propias comprobaciones pudiéndose ayudar del service mesh para esta tarea.
Comunicación entre microservicios desplegados en el mismo namespace de Openshift
Esta comunicación se realiza entre microservicios Backend que pertenecen al mismo dominio funcional, es decir, son microservicios que pertenecen al mismo proyecto de desarrollo y trabajan habitualmente juntos.
Este caso de uso implica que las peticiones no salen al exterior y se mantienen dentro del contexto privado del propio namespace de Openshift, por lo tanto, no se requiere la utilización de una API publicada en el API Manager. En este caso, el papel para verificar la comunicación puede recaer en el service mesh que analizará la petición y determinará si debe dejar que llegue o no al microservicio.
Al igual que las comunicaciones públicas, todas las comunicaciones internas estarán securizadas mediante token JWT, mTSL o algún mecanismo de seguridad similar que garantice que se cumple el principio de Zero Trust, Si bien el service mesh garantiza hasta cierto punto la seguridad y protege al microservicio para que no le llegue una petición no autorizada, el microservicio debe implementar también sus propios mecanismos de seguridad que completan los que realiza el service mesh.
Comunicación entre microservicios desplegados en diferentes namespace de Openshift pero pertenecientes al mismo dominio funcional o proyecto.
Es posible, si se autoriza previamente, tener un proyecto dividido en varios namespaces. Para que no se produzcan problemas de rendimiento y comunicación, estos namespaces aunque estén separados de forma física tienen que poder comunicarse entre ellos como si fuesen uno solo a nivel lógico.
Al pertenecer todos los namespaces al mismo proyecto y estar gestionados por el mismo equipo de desarrollo, se considera que entre ellos puede establecerse una burbuja de seguridad que abarque todos los namespaces que gestiona el proyecto. En este caso, tampoco se requiere publicar las API que utilizan estos microservicios para comunicarse entre sí en el API Manager y se les aplicaría a las comunicaciones las mismas restricciones indicadas cuando los microservicios desplegados pertenecen al mismo namespace de Openshift.
Comunicación entre microservicios pertenecientes a diferente dominio funcional o proyecto.
Cuando dos microservicios pertenezcan a diferentes dominios funcionales obligatoriamente estarán desplegados en diferentes namespaces de Openshift. En este caso, la comunicación entre ambos dominios se considera pública, y obligatoriamente deberá estar gestionada a través de una API gestionada por el API Manager y gobernada por la Oficina de Interoperabilidad.
Deberá analizarse, por parte del equipo de desarrollo, qué información van a publicar sus microservicios para que sea consultada por otros dominios funcionales y crear las API necesarias, siguiendo los criterios establecidos por la Arquitectura de API, desplegándolas en el API Manager siguiendo las directrices indicadas en el Modelo de Despliegue de API.
La comunicación entre microservicios de proyectos distintos siempre tiene que estar securizada mediante token JWT, mTLS o algún mecanismo de seguridad similar que garantice que se cumple el principio de Zero Trust, y aunque API Manager haga una comprobación de seguridad el microservicio deberá también hacer sus propias comprobaciones pudiéndose ayudar del service mesh para esta tarea.
Comunicación entre un microservicio y un servicio legacy
Se engloba en este caso de uso la comunicación entre un microservicio y un servicio que, por encontrarse obsoleto, queda fuera de las arquitecturas de referencias definidas por la Oficina de Arquitectura, y no puede realizarse a través de una API publicada en el API Manager.
En este caso, el equipo de desarrollo deberá comunicarse con la Oficina de Interoperabilidad para que se cree un conector en el bus de interoperabilidad que permita dicha comunicación. Esta comunicación estará gobernada por la Oficina de Interoperabilidad que guiará al equipo de desarrollo sobre la mejor forma de realizarse.
Sea como sea, al igual que el resto de las comunicaciones, estas deberán estar securizadas mediante token JWT, mTLS o algún mecanismo de seguridad similar que garantice que se cumple el principio de Zero Trust, y aunque API Manager haga una comprobación de seguridad el microservicio deberá también hacer sus propias comprobaciones pudiéndose ayudar del service mesh para esta tarea.
Comunicación entre un microservicio y un servicio externo
La comunicación entre un microservicio y cualquier servicio a la ADA externo se considerará una comunicación pública y deberá notificarse a la Oficina de Interoperabilidad. No se permite la comunicación directa entre ambos servicios ya que dicha comunicación debe ser gobernada por la Oficina de Interoperabilidad que indicará al equipo de desarrollo la mejor forma de realizarse. Habitualmente esta comunicación se realizará utilizando el API Manager o el Bus de Interoperabilidad.
Independientemente del mecanismo que la Oficina de Interoperabilidad establezca, estas comunicaciones estas deberán estar securizadas mediante token JWT, mTLS o algún mecanismo de seguridad similar que garantice que se cumple el principio de Zero Trust, y aunque API Manager haga una comprobación de seguridad el microservicio deberá también hacer sus propias comprobaciones pudiéndose ayudar del service mesh para esta tarea.
Proceso de instalación y despliegue
Entorno pre-cloud
Prerrequisitos que deben cumplirse antes de iniciar el proceso de despliegue:
- En el entorno donde se va a desplegar, el proyecto debe tener un namespace de Openshift asignado. El nombre de este namespace debe cumplir los requisitos de nomenclatura. Si no existe este namespace debe solicitarse su creación.
- El microservicio que se va a desplegar tiene que tener asociado un proyecto en Git. El nombre de este proyecto debe cumplir los requisitos de nomenclatura y todo el repositorio tiene que seguir los criterios establecidos por la estrategia de ramificación.
A continuación se listan los pasos que deben seguirse para desplegar un microservicio.
- Ponerse en contacto con DevSecOps para notificar el despliegue del microservicio y solicitarles los siguientes elementos:
- Creación de una instancia de la pipeline de camino único en Jenkins.
- Creación del despliegue en ArgoCD.
- En el repositorio git deben crearse el Webhook con los siguientes datos:
- URL: Instancia de la pipeline proporcionada por DevSecOps
- Check que deben estar marcados: Tag push events, Merge request events y Enable SSL verification.
- El microservicio debe tener configurado los siguientes elementos. Los microservicios que utilicen el framework de desarrollo ada-fwk-ms al ejecutar uno de los arquetipos maven publicados se creará un microservicio con todos los ficheros obligatorios creados y una configuración por defecto. Esta configuración deberá ser revisada y adaptada por el equipo de desarrollo:
- Fichero dockerfile: Contiene la imagen base para el despliegue del microservicio y cualquier otro elemento necesario para la generación de la imagen.
- Fichero ci.json: Contiene la configuración de los parámetros de entrada para la correcta ejecución de la pipeline de Jenkins.
- Fichero sonar.properties: Contiene la configuración para que la pipeline pueda ejecutar correctamente el paso de validación de calidad del código en Sonarcube.
- Directorio despliegue: Este directorio contiene una carpeta para cada entorno (test, pre y pro). Cada carpeta contiene los ficheros necesarios para el despliegue en ese entorno. El contenido de esta carpeta sigue el patrón de despliegue de Kubernetes Kustomize.
- Iniciar el proceso de despliegue siguiendo el procedimiento indicado en la documentación relativa a la estrategia de ramificación y verificar tanto en Jenkins como en ArgoCD y Openshift que el proceso de despliegue se está ejecutando correctamente.
Para más información sobre estos ficheros consultar la documentación publicada por DevSecOps y la documentación oficial de Red Hat Openshift y Kubernetes.
ANEXO. Tipos de escalado y dimensionamiento de un pod.
Escalado vertical
El escalado vertical es el que, manteniendo el mismo número de réplicas, dota de más recursos a cada réplica incrementando su cpu y memoria. Este tipo de escalado debe usarse cuando se considera que los pods necesitan más recursos para hacer su trabajo en condiciones normales. Este problema se manifiesta por no haber realizado una buena estimación de los recursos cuando se implantó el microservicio por primera vez o como producto de un aumento del consumo después de haberle incorporado una nueva característica.
La modificación del dimensionamiento vertical se realiza cuando se detecte problemas de rendimiento continuado en los pods y que no se puedan asociar a un exceso de carga en los mismos.
Los campos que pueden dimensionarse verticalmente son:
- Cpu: Representa la cantidad de núcleos de procesador que el pod necesita para funcionar correctamente. La unidad de medida para los recursos de CPU en Kubernetes se puede expresar en términos de "núcleos" o "milinúcleos" (milicores)
- Memory: Representa la cantidad de memoria que necesita el pod para funcionar correctamente. La unidad de medida es el byte, pudiendo usar toda su escala (byte, kilobyte, megabyte…)
En concreto, el escalado vertical de un pod se configura con las siguientes propiedades:
- resources.limits: Cantidad máxima de recursos (cpu y memoria) que puede usar un pod. Esto significa que el pod nunca podrá consumir más recursos de los indicados en este parámetro.
- resources.requests: Es la mínima cantidad de recursos (cpu y memoria) que un pod toma. Cuando el pod se levante, automáticamente se reserva para sí mismo la cantidad de recursos especificados en este campo.
Lo habitual es manejar un rango de recursos usando resources.request como valor inferior y resources.limits como valor superior en una horquilla que será manejada por la plataforma automáticamente tomando y liberando recursos dentro de ese margen.
A continuación se muestran los valores que se asignarán por defecto a los microservicios para su escalado vertical. Estos valores deberán revisarse en cada microservicio que se despliegue para ajustarlos a sus necesidades concretas:
Propiedad | Valor | Descripción |
resources.request.cpu | 100m | Se reservará como mínimo 100 milicores para el arranque del microservicio. |
resources.request.memory | 256Mi | Se reservará como mínimo 256MB de memoria para el arranque del microservicio. |
resources.limits.cpu | 0.5m | Como máximo, el microservicio podrá reclamar el uso de 500 milicores para la ejecución de sus procesos. |
resource.limits.memory | 2Gi para Jvm 21 | Como máximo, el microservicio podrá reclamar el uso de 2 GB de memoria para la ejecución de sus procesos si está implementado usando jvm 21. |
Escalado horizontal
El escalado horizontal se produce cuando se modifica el número de réplicas de un pod para ajustarlo a un pico en la demanda. Este tipo de escalado debe usarse cuando el problema no está relacionado con la cantidad de recursos asociados a un pod sino con la cantidad de demanda que hay del mismo. Este escalado permite, al aumentar o disminuir las réplicas del pod, repartir la carga de trabajo en tiempo real.
En producción se configurará el escalado automático para que aumente las réplicas cuando se detecte picos de aumento en el consumo superior al 80% del resources.limits configurado. Se bajará el número de replicas, manteniendo siempre el mínimo establecido para ese entorno, cuando se detecte que el consumo del microservicio ha bajado al 50% del resources.limits configurado.
Entorno | Mínimo de réplicas |
Test | 1 |
Preproducción | 3 |
Producción | 3 |
Dimensionado de la JVM
Un elemento fundamental para la optimización de un microservicio es configurar la JVM sobre la que corre de forma apropiada. Por ello, se recomienda establecer unos valores para los siguientes parámetros de la JVM:
Propiedad | Valor Jvm11 | Valor Jvm21 | Descripción |
-Xms | 256MB | 256MB | Tamaño inicial de memoria disponible para la JVM. |
-Xmx | 1GB | 2GB | Tamaño máximo de memoria disponible para la JVM. |
-Xss | 256KB | 256KB | Tamaño de la pila de ejecución de hilos. |